package com.alibaba.dubbo.dynamic.service.impl;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.dynamic.config.DynamicExportConfig;
import com.alibaba.dubbo.dynamic.dao.DynamicDao;
import com.alibaba.dubbo.dynamic.dao.DynamicJarDao;
import com.alibaba.dubbo.dynamic.model.Dynamic;
import com.alibaba.dubbo.dynamic.model.query.DynamicExample;
import com.alibaba.dubbo.dynamic.service.DynamicExportService;
import com.alibaba.dubbo.dynamic.service.DynamicJarService;
import com.alibaba.dubbo.dynamic.service.DynamicService;
import com.alibaba.dubbo.dynamic.service.JarService;
import com.alibaba.dubbo.remoting.zookeeper.ZookeeperClient;
import com.alibaba.fastjson.JSONObject;
import org.apache.zookeeper.KeeperException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created on 2016/8/14 07:29.
 */
@RestController
public class DynamicServiceImpl extends BaseRestImpl<Dynamic, DynamicExample, Integer> implements DisposableBean, DynamicService {

    @Autowired
    private DynamicDao dynamicDao;

    @Autowired
    private DynamicJarDao dynamicJarDao;

    @Autowired
    private JarService jarService;

    @Autowired
    private DynamicJarService dynamicJarService;

    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    private ZookeeperClient zookeeperClient;

    @Value("${server.port}")
    private int port;

    private String dynamicRootPath = "/dubbo/com.alibaba.dubbo.dynamic.service.DynamicExportService";
    private String dynamicServicePath = dynamicRootPath + "/providers";

    private String undeployPath = dynamicRootPath + "/undeploy";

    private Map<String, ReferenceBean<DynamicExportService>> serviceMap = new ConcurrentHashMap<String, ReferenceBean<DynamicExportService>>();

    @Override
    public Object insertSelective(@RequestBody Dynamic dynamic) {
        String interfaceName = dynamic.getInterfaceName();
        String serviceName = dynamic.getServiceName();
        if (interfaceName == null || serviceName == null) {
            throw new RuntimeException("参数非法!");
        }
        return super.insertSelective(dynamic);
    }

    @GetMapping(value = "/listUnDynamicService")
    public List<Dynamic> listUnDynamicService() {
        return dynamicDao.selectByExample(new DynamicExample());
    }

    @GetMapping(value = "/export/{ids}")
    public Map<String, Object> export(@PathVariable(value = "ids") List<Integer> dynamicsIds, @RequestBody List<String> serverUrls) throws InterruptedException, IOException, KeeperException {

        for (String serverUrl : serverUrls) {
            DynamicExportService dynamicExportService = getDynamicExportService(serverUrl);
            List<DynamicExportConfig> exportConfigs = new ArrayList<DynamicExportConfig>();
            for (Dynamic dynamic : dynamicDao.selectByPrimaryKeys(dynamicsIds)) {
                String beanId = dynamic.getBeanId();
                String groupName = dynamic.getGroupName();
                String interfaceName = dynamic.getInterfaceName();
                String serviceName = dynamic.getServiceName();
                String protocol = dynamic.getProtocol();
                Integer timeout = dynamic.getTimeout();
                String version = dynamic.getVersion();
                String filter = dynamic.getFilter();
                boolean renewClassLoader = dynamic.getRenewClassLoader() != null;
                DynamicExportConfig config = new DynamicExportConfig(beanId, protocol, interfaceName, serviceName, groupName, version, timeout, filter, renewClassLoader);
                exportConfigs.add(config);
            }
            List<String> jarUrls = dynamicJarService.selectJarsUrlByDynamicId(dynamicsIds);
            return dynamicExportService.export(exportConfigs);
        }
        return new HashMap<String, Object>();
    }

    @GetMapping(value = "/listDynamicBean")
    public List<Map<String, Object>> listDynamicBean() throws InterruptedException, IOException, KeeperException {
        List<JSONObject> dynamicServices = listDynamicService();
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

        for (JSONObject json : dynamicServices) {
            String url = json.getString("url");
            List<Map<String, Object>> maps = getDynamicExportService(url).listDynamicBean();
            for (Map<String, Object> map : maps) {
                map.put("dynamicServiceUrl", url);
            }
            list.addAll(maps);
        }
        return list;
    }


    @GetMapping(value = "/listDynamicService")
    public List<JSONObject> listDynamicService() throws IOException, KeeperException, InterruptedException {
        List<String> children = zookeeperClient.getChildren(dynamicServicePath);
        List<JSONObject> dys = new ArrayList<JSONObject>();
        for (String dy : children) {
            URL url = URL.valueOf(URL.decode(dy));
            JSONObject json = new JSONObject();
            String application = url.getParameter("application");
            String timestamp = url.getParameter("timestamp");
            json.put("port", url.getPort());
            json.put("host", url.getHost());
            json.put("url", url.toServiceString());
            json.put("fullUrl", url.toFullString());
            json.put("application", application);
            json.put("timestamp", timestamp);

            dys.add(json);
        }
        return dys;
    }

    @GetMapping(value = "/unexport")
    public ResponseEntity<String> unexport(@RequestParam(value = "id") String id, @RequestParam(value = "url") String url) {
        DynamicExportService dynamicExportService = getDynamicExportService(url);
        if (dynamicExportService != null) {
            dynamicExportService.unexport(Arrays.asList(id));
        }
        return new ResponseEntity<String>(HttpStatus.OK);
    }


    public DynamicExportService getDynamicExportService(String url) {
        ReferenceBean<DynamicExportService> cacheBean = serviceMap.get(url);
        if (cacheBean != null) {
            return cacheBean.get();
        }
        ReferenceBean<DynamicExportService> referenceBean = new ReferenceBean<DynamicExportService>();
        referenceBean.setApplicationContext(this.applicationContext);
        referenceBean.setInterface(DynamicExportService.class);
        referenceBean.setUrl(url);
        referenceBean.setApplication(new ApplicationConfig("dynamic-ref"));
        serviceMap.put(url, referenceBean);
        return referenceBean.get();
    }


    public void destroy() throws Exception {
        for (String key : serviceMap.keySet()) {
            try {
                serviceMap.remove(key).destroy();
            } catch (Exception e) {
            }
        }
    }

    public void setDao() {
        this.baseDao = dynamicDao;
    }
}